<?php


namespace app\api\logic;

use app\model\pms\Goods;
use app\model\pms\GoodsTag;
use plugin\coupon\app\model\Coupon;
use plugin\coupon\app\model\CouponGoods;
use support\constants\QueueKey;
use support\constants\RedisKey;
use support\Container;
use support\Log;
use support\Redis;
use support\service\MqClient;
use support\utils\Form;
use support\utils\MsClient;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\db\Query;

/**
 * 使用搜索引擎搜索商品
 * Class SearchController
 * @package app\api\controller
 */
class GoodsSearchLogic
{
    public function goodsPage(Form $form)
    {
        if ($form['search']) {
            //增加搜索记录
            Redis::zIncrBy(RedisKey::SEARCH_KEYWORD_KEY, 1, $form['search']);
        }
        $filter = [
            ['is_show=1'],
            ['is_del=0'],
        ];
        $search = $form['search'] ?? "";
        $form['cate_id1'] && $filter[] = "cate_id1=" . $form['cate_id1'];
        $form['cate_id2'] && $filter[] = "cate_id2=" . $form['cate_id2'];
        $form['cate_id3'] && $filter[] = "cate_id3=" . $form['cate_id3'];
        if ($form['tag_ids']) {
            $tagFilter = [];
            foreach (strToArr($form['tag_ids']) as $item) {
                $tagFilter[] = "tag_ids = {$item}";
            }
            $filter[] = $tagFilter;
        }
        if ($form['coupon_id'] && class_exists(Coupon::class)) {
            $filter = $this->couponFilter($form['coupon_id'], $filter);
        }
        $filter = $this->formatFilter($form, $filter);

        $sort = [];
        //综合排序
        if ($form['sortfield'] === 'comprehensive') {
            $sort = ["sales:desc", "min_price:asc"];
        }
        if ($form['sortfield'] === 'price') {
            $sort = ["min_price:{$form->getOrder('asc')}"];
        }
        //销量排序
        if ($form['sortfield'] === 'sales') {
            $sort = ["{$form['sortfield']}:{$form->getOrder('asc')}"];
        }

        //使用搜索引擎查询出分页数据
        $docs = MsClient::client()->index('goods')
            ->search($search, [
                'filter' => $filter,
                'sort' => $sort,
                "hitsPerPage" => $form->getPageSize(),
                "page" => $form->getPage(),
                "attributesToRetrieve" => [
                    'id'
                ],
                "attributesToSearchOn" => [
                    "name",
                    "sub_name",
                ]
            ]);

        $count = $docs->getTotalHits();
        //使用id查询具体mysql的数据
        $ids = array_column($docs->getHits(), 'id');
        $query = Goods::where([
            ['id', 'in', $ids]
        ]);
        $query->orderField("id", $ids, "ASC");
        $query->field('*');
        $with = array_merge([
            "brand" => function (Query $query) {
                $query->field(['id', 'name']);
            },
        ], Goods::getCateWith());

        $with = $this->formatWith($form, $with);
        $query->with($with);
        $data = $query->select();
        return [
            "total" => $count,
            "has_more" => $form->getPage() < ((int)ceil($count / $form->getPageSize())),
            'records' => $data
        ];
    }

    static function sync($goodsIds)
    {
        $goodsList = Goods::with(array_merge(Goods::getCateWith(), [
            'brand'
        ]))
            ->where('id', 'in', $goodsIds)
            ->select()
            ->toArray();

        $res = self::goodsSync($goodsList);
        dump("同步商品成功:" . json_encode($goodsIds) . " 返回结果:" . json_encode($res));
        Log::info("同步商品成功:" . json_encode($goodsIds) . " 返回结果:" . json_encode($res));
    }

    /**
     * 商品全量同步
     */
    static function fullSync()
    {
        $goodsList = Goods::with(array_merge(Goods::getCateWith(), [
            'brand'
        ]))
            ->select()
            ->toArray();
        $res = self::goodsSync($goodsList);
        dump($res);
    }

    private static function goodsSync($goodsList)
    {
        $tags = GoodsTag::select()->toArray();
        $tagList = array_column($tags, 'name', 'id');
        $docs = [];
        foreach ($goodsList as $item) {
            $tagsIds = $item['tag_ids'];
            $tags_name = [];
            foreach ($tagsIds as $tag) {
                if ($cur = $tagList[$tag] ?? "") {
                    $tags_name[] = $cur;
                }
            }
            $docs[] = [
                "id" => $item['id'],
                "name" => $item['name'],
                "sub_name" => $item['sub_name'],
                "cate_id1" => $item['cate_id1'],
                "cate_id2" => $item['cate_id2'],
                "cate_id3" => $item['cate_id3'],
                "cate_id1_name" => $item['cate1']['name'] ?? "",
                "cate_id2_name" => $item['cate2']['name'] ?? "",
                "cate_id3_name" => $item['cate3']['name'] ?? "",
                "brand_id" => $item['brand_id'],
                "brand_name" => $item['brand']['name'] ?? "",
                "min_price" => $item['min_price'] ?? 0,
                "max_price" => $item['max_price'] ?? 0,
                "sales" => $item['sales'] ?? 0,
                "tag_ids" => $tagsIds,
                "tags_name" => $tags_name,
                "is_show" => $item['is_show'],
                "is_del" => $item['is_del'],
                "is_agent" => $item['is_agent'] ?? 0,
            ];
        }
        $settings = [
            //设置允许查询字段
            'filterableAttributes' => [
                "name",
                "sub_name",
                "cate_id1",
                "cate_id2",
                "cate_id3",
                "brand_id",
                "tag_ids",
                "is_show",
                "is_del",
                "is_agent",
                "id",
            ],
            //设置允许排序的字段
            'sortableAttributes' => [
                'min_price',
                'max_price',
                'sales',
            ],
            //设置排序优先级
            'rankingRules' => [
                'sort', //自定义sort优先
                'words', //关键词相关度优先
                'typo', //错词容忍度
                'proximity',
                'attribute',
                'exactness'
            ]
        ];
        $index = MsClient::client()->index('goods');
        $index->updateSettings($settings);
        return $index->addDocuments($docs);

    }

    /**
     * 增加商品变动 用于定时任务同步搜索商品
     * @param array $goodsIds
     */
    static function addGoodsChange(array $goodsIds)
    {
        foreach ($goodsIds as $goodsId) {
            Redis::sAdd(RedisKey::SEARCH_SYNC, $goodsId);
        }
        Container::get(MqClient::class)->send(QueueKey::GOODS_SYNC, [
            'ids' => $goodsIds,
        ]);
    }

    /**
     * 优惠券条件查询
     * @param $coupon_id
     * @param $filter
     * @return mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function couponFilter($coupon_id, $filter)
    {
        $couponModel = new Coupon();
        $coupon = $couponModel->where([
            'id' => $coupon_id,
        ])
            ->field([
                'goods_category_ids',
                'goods_brand_ids',
                'goods_tag_ids',
                'join_goods',
            ])
            ->find();
        if (!$coupon) {
            return $filter;
        }
        if ($coupon['join_goods'] == Coupon::JOIN_GOODS_ALL) {
            if ($coupon['goods_category_ids']) {
                $cateFilter = [];
                foreach (strToArr($coupon['goods_category_ids']) as $id) {
                    $cateFilter[] = "cate_id1 = {$id} OR cate_id2 = {$id} OR cate_id3 = {$id}";
                }
                $filter[] = $cateFilter;
            }
            if ($coupon['goods_brand_ids']) {
                $brandFilter = [];
                foreach (strToArr($coupon['goods_brand_ids']) as $id) {
                    $brandFilter[] = "brand_id = {$id}";
                }
                $filter[] = $brandFilter;
            }
            if ($coupon['goods_tag_ids']) {
                $couponTagFilter = [];
                foreach (strToArr($coupon['goods_tag_ids']) as $item) {
                    $couponTagFilter[] = "tag_ids = {$item}";
                }
                $filter[] = $couponTagFilter;
            }
        } else {
            $ids = CouponGoods::where([
                'coupon_id' => $coupon_id
            ])
                ->column('goods_id');
            if ($ids) {
                $goodsFilter = [];
                foreach ($ids as $id) {
                    $goodsFilter[] = "id = {$id}";
                }
                $filter[] = $goodsFilter;
            }
        }

        return $filter;
    }

    protected function formatWith(Form $form, array $with)
    {
        return $with;
    }

    protected function formatFilter(Form $form, array $filter)
    {
        return $filter;
    }
}